package com.aiwu

import android.util.SparseArray
import android.view.KeyEvent
import android.view.MotionEvent
import com.aiwu.library.App
import com.aiwu.library.HandleMapManager
import com.aiwu.library.abs.AbsInputAxisManager
import com.aiwu.library.bean.Direction
import com.aiwu.library.bean.RockerOperateButtonBean
import org.citra.citra_emu.NativeLibrary
import org.citra.citra_emu.R


/**
 * 输入管理
 * 帧数可能比较低 按键的间隔时间尽量拉大
 */
class InputManager private constructor() : AbsInputAxisManager() {
    private var mTouchscreenPointerId = -1
    override fun initBtnMapper(btnMap: HashMap<String, Int>) {
        btnMap[KEY_A] = NativeLibrary.ButtonType.BUTTON_A
        btnMap[KEY_B] = NativeLibrary.ButtonType.BUTTON_B
        btnMap[KEY_X] = NativeLibrary.ButtonType.BUTTON_X
        btnMap[KEY_Y] = NativeLibrary.ButtonType.BUTTON_Y
        btnMap[KEY_L] = NativeLibrary.ButtonType.TRIGGER_L
        btnMap[KEY_R] = NativeLibrary.ButtonType.TRIGGER_R
        btnMap[KEY_ZL] = NativeLibrary.ButtonType.BUTTON_ZL
        btnMap[KEY_ZR] = NativeLibrary.ButtonType.BUTTON_ZR
        btnMap[KEY_SELECT] = NativeLibrary.ButtonType.BUTTON_SELECT
        btnMap[KEY_START] = NativeLibrary.ButtonType.BUTTON_START
        btnMap[KEY_HOME] = NativeLibrary.ButtonType.BUTTON_HOME
    }

    override fun initDirectionMapper(directionMap: HashMap<String, Array<Int>>) {
        directionMap[Direction.DIRECTION_UP.name] = arrayOf(NativeLibrary.ButtonType.DPAD_UP)
        directionMap[Direction.DIRECTION_UP_RIGHT.name] =
            arrayOf(NativeLibrary.ButtonType.DPAD_UP, NativeLibrary.ButtonType.DPAD_RIGHT)
        directionMap[Direction.DIRECTION_RIGHT.name] =
            arrayOf(NativeLibrary.ButtonType.DPAD_RIGHT)
        directionMap[Direction.DIRECTION_DOWN_RIGHT.name] = arrayOf(
            NativeLibrary.ButtonType.DPAD_DOWN,
            NativeLibrary.ButtonType.DPAD_RIGHT
        )
        directionMap[Direction.DIRECTION_DOWN.name] =
            arrayOf(NativeLibrary.ButtonType.DPAD_DOWN)
        directionMap[Direction.DIRECTION_DOWN_LEFT.name] = arrayOf(
            NativeLibrary.ButtonType.DPAD_DOWN,
            NativeLibrary.ButtonType.DPAD_LEFT
        )
        directionMap[Direction.DIRECTION_LEFT.name] = arrayOf(NativeLibrary.ButtonType.DPAD_LEFT)
        directionMap[Direction.DIRECTION_UP_LEFT.name] =
            arrayOf(
                NativeLibrary.ButtonType.DPAD_UP,
                NativeLibrary.ButtonType.DPAD_LEFT
            )
    }

    override fun initBurstMapper(burstMap: HashMap<Int, Int>) {
        burstMap[VALUE_BURST_A] = NativeLibrary.ButtonType.BUTTON_A
        burstMap[VALUE_BURST_B] = NativeLibrary.ButtonType.BUTTON_B
        burstMap[VALUE_BURST_X] = NativeLibrary.ButtonType.BUTTON_X
        burstMap[VALUE_BURST_Y] = NativeLibrary.ButtonType.BUTTON_Y
        burstMap[VALUE_BURST_L] = NativeLibrary.ButtonType.TRIGGER_L
        burstMap[VALUE_BURST_R] = NativeLibrary.ButtonType.TRIGGER_R
        burstMap[VALUE_BURST_ZL] = NativeLibrary.ButtonType.BUTTON_ZL
        burstMap[VALUE_BURST_ZR] = NativeLibrary.ButtonType.BUTTON_ZR
    }

    override fun initKeyEventSet(keyEventSet: HashSet<Int>) {
        keyEventSet.addAll(mBtnMap.values)
        keyEventSet.add(NativeLibrary.ButtonType.DPAD_UP)
        keyEventSet.add(NativeLibrary.ButtonType.DPAD_DOWN)
        keyEventSet.add(NativeLibrary.ButtonType.DPAD_LEFT)
        keyEventSet.add(NativeLibrary.ButtonType.DPAD_RIGHT)
        keyEventSet.addAll(mBurstMap.keys)
    }

    override fun initMotionEvents(motionEvents: SparseArray<Float>) {
        motionEvents.put(NativeLibrary.ButtonType.STICK_LEFT_UP, AXIS_VALUE_DEFAULT_UP_LEFT)
        motionEvents.put(NativeLibrary.ButtonType.STICK_LEFT_DOWN, AXIS_VALUE_DEFAULT_DOWN_RIGHT)
        motionEvents.put(NativeLibrary.ButtonType.STICK_LEFT_LEFT, AXIS_VALUE_DEFAULT_UP_LEFT)
        motionEvents.put(NativeLibrary.ButtonType.STICK_LEFT_RIGHT, AXIS_VALUE_DEFAULT_DOWN_RIGHT)
        motionEvents.put(NativeLibrary.ButtonType.STICK_C_UP, AXIS_VALUE_DEFAULT_UP_LEFT)
        motionEvents.put(NativeLibrary.ButtonType.STICK_C_DOWN, AXIS_VALUE_DEFAULT_DOWN_RIGHT)
        motionEvents.put(NativeLibrary.ButtonType.STICK_C_LEFT, AXIS_VALUE_DEFAULT_UP_LEFT)
        motionEvents.put(NativeLibrary.ButtonType.STICK_C_RIGHT, AXIS_VALUE_DEFAULT_DOWN_RIGHT)
    }

    override fun onSaveFastStateShortcut() {
        StateManager.instance.saveFastState()
    }

    override fun onLoadFastStateShortcut() {
        StateManager.instance.loadFastState()
    }

    override fun sendKeyEventToEmulator(
        isFromVirtualGamePad: Boolean,
        player: Int,
        isDown: Boolean,
        vararg keyCodes: Int
    ) {
        keyCodes.forEach {
            NativeLibrary.onGamePadEvent(
                NativeLibrary.TouchScreenDevice, it,
                if (isDown) NativeLibrary.ButtonState.PRESSED else NativeLibrary.ButtonState.RELEASED
            )
        }
    }

    override fun sendKeyEventToEmulator(
        isFromVirtualGamePad: Boolean,
        player: Int,
        isDown: Boolean,
        keyCodes: Array<Int?>
    ) {
        keyCodes.forEach {
            it?.let {
                NativeLibrary.onGamePadEvent(
                    NativeLibrary.TouchScreenDevice, it,
                    if (isDown) NativeLibrary.ButtonState.PRESSED else NativeLibrary.ButtonState.RELEASED
                )
            }
        }
    }

    override fun isResolveOnDirectionEvent(rockerBean: RockerOperateButtonBean): Boolean {
        return KEY_ROCKER_CROSS == rockerBean.id
    }

    override fun resolveOnAxisChanged(
        player: Int,
        xAxisRatio: Float,
        yAxisRatio: Float,
        rockerBean: RockerOperateButtonBean
    ) {
        if (KEY_ROCKER_MAIN == rockerBean.id) {
            NativeLibrary.onGamePadMoveEvent(
                NativeLibrary.TouchScreenDevice,
                NativeLibrary.ButtonType.STICK_LEFT,
                xAxisRatio,
                yAxisRatio
            )
        } else if (KEY_ROCKER_C == rockerBean.id) {
            NativeLibrary.onGamePadMoveEvent(
                NativeLibrary.TouchScreenDevice,
                NativeLibrary.ButtonType.STICK_C,
                xAxisRatio,
                yAxisRatio
            )
        }
    }

    override fun resolveOnAxisFinish(player: Int, rockerBean: RockerOperateButtonBean) {
        if (KEY_ROCKER_MAIN == rockerBean.id) {
            NativeLibrary.onGamePadMoveEvent(
                NativeLibrary.TouchScreenDevice,
                NativeLibrary.ButtonType.STICK_LEFT,
                0f,
                0f
            )
        } else if (KEY_ROCKER_C == rockerBean.id) {
            NativeLibrary.onGamePadMoveEvent(
                NativeLibrary.TouchScreenDevice,
                NativeLibrary.ButtonType.STICK_C,
                0f,
                0f
            )
        }
    }

    override fun resolveOnMotionEvent(player: Int, code: Int, value: Float) {
        when (code) {
            NativeLibrary.ButtonType.STICK_LEFT_UP, NativeLibrary.ButtonType.STICK_LEFT_DOWN ->
                NativeLibrary.onGamePadMoveEvent25(
                    NativeLibrary.TouchScreenDevice,
                    NativeLibrary.ButtonType.STICK_LEFT,
                    value,
                    false
                )

            NativeLibrary.ButtonType.STICK_LEFT_LEFT, NativeLibrary.ButtonType.STICK_LEFT_RIGHT ->
                NativeLibrary.onGamePadMoveEvent25(
                    NativeLibrary.TouchScreenDevice,
                    NativeLibrary.ButtonType.STICK_LEFT,
                    value,
                    true
                )

            NativeLibrary.ButtonType.STICK_C_UP, NativeLibrary.ButtonType.STICK_C_DOWN ->
                NativeLibrary.onGamePadMoveEvent25(
                    NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.STICK_C, value, false
                )

            NativeLibrary.ButtonType.STICK_C_LEFT, NativeLibrary.ButtonType.STICK_C_RIGHT ->
                NativeLibrary.onGamePadMoveEvent25(
                    NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.STICK_C, value, true
                )

            else -> {}
        }
    }

    /**
     * 触摸屏幕
     *
     * @param event
     */
    fun onTouchEvent(event: MotionEvent) {
        val pointerIndex = event.actionIndex
        when (event.action and MotionEvent.ACTION_MASK) {
            MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN -> {
                if (mTouchscreenPointerId == -1 &&
                    NativeLibrary.onTouchEvent(
                        event.getX(pointerIndex),
                        event.getY(pointerIndex),
                        true
                    )
                ) {
                    mTouchscreenPointerId = event.getPointerId(pointerIndex)
                }
            }

            MotionEvent.ACTION_UP, MotionEvent.ACTION_POINTER_UP -> {
                if (mTouchscreenPointerId == event.getPointerId(pointerIndex)) {
                    // We don't really care where the touch has been released. We only care whether it has been
                    // released or not.
                    NativeLibrary.onTouchEvent(0f, 0f, false)
                    mTouchscreenPointerId = -1
                }
            }
        }
        for (i in 0 until event.pointerCount) {
            if (mTouchscreenPointerId == event.getPointerId(i)) {
                NativeLibrary.onTouchMoved(event.getX(i), event.getY(i))
            }
        }
    }

    companion object {
        const val KEY_A = "A"
        const val KEY_B = "B"
        const val KEY_X = "X"
        const val KEY_Y = "Y"
        const val KEY_L = "L"
        const val KEY_R = "R"
        const val KEY_ZL = "ZL"
        const val KEY_ZR = "ZR"
        const val KEY_SELECT = "SELECT"
        const val KEY_START = "START"
        const val KEY_HOME = "HOME"
        const val KEY_ROCKER_CROSS = "ROCKER_CROSS"
        const val KEY_ROCKER_MAIN = "ROCKER_MAIN"
        const val KEY_ROCKER_C = "ROCKER_C"

        //region 虚拟的连发键
        private const val VALUE_BURST_A = 100
        private const val VALUE_BURST_B = 101
        private const val VALUE_BURST_X = 102
        private const val VALUE_BURST_Y = 103
        private const val VALUE_BURST_L = 104
        private const val VALUE_BURST_R = 105
        private const val VALUE_BURST_ZL = 106
        private const val VALUE_BURST_ZR = 107

        val instance: InputManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
            InputManager()
        }

        /**
         * 按键和按键图片的map
         */
        fun getKeyBitmapNameMap(): HashMap<String, String> {
            val keyMap = HashMap<String, String>()
            keyMap[KEY_A] = "button_a"
            keyMap[KEY_B] = "button_b"
            keyMap[KEY_X] = "button_x"
            keyMap[KEY_Y] = "button_y"
            keyMap[KEY_SELECT] = "button_select"
            keyMap[KEY_START] = "button_start"
            keyMap[KEY_HOME] = "button_home"
            keyMap[KEY_L] = "button_l"
            keyMap[KEY_R] = "button_r"
            keyMap[KEY_ZL] = "button_zl"
            keyMap[KEY_ZR] = "button_zr"
            return keyMap
        }

        fun getGameKeys(): LinkedHashMap<String, Int> {
            val map = LinkedHashMap<String, Int>()
            map[App.getContext().getString(R.string.emu_lib_key_name_cross_up)] =
                NativeLibrary.ButtonType.DPAD_UP
            map[App.getContext().getString(R.string.emu_lib_key_name_cross_down)] =
                NativeLibrary.ButtonType.DPAD_DOWN
            map[App.getContext().getString(R.string.emu_lib_key_name_cross_left)] =
                NativeLibrary.ButtonType.DPAD_LEFT
            map[App.getContext().getString(R.string.emu_lib_key_name_cross_right)] =
                NativeLibrary.ButtonType.DPAD_RIGHT
            map[KEY_A] =
                NativeLibrary.ButtonType.BUTTON_A
            map[KEY_B] = NativeLibrary.ButtonType.BUTTON_B
            map[KEY_X] =
                NativeLibrary.ButtonType.BUTTON_X
            map[KEY_Y] =
                NativeLibrary.ButtonType.BUTTON_Y
            map[KEY_L] =
                NativeLibrary.ButtonType.TRIGGER_L
            map[KEY_R] =
                NativeLibrary.ButtonType.TRIGGER_R
            map[KEY_ZL] =
                NativeLibrary.ButtonType.BUTTON_ZL
            map[KEY_ZR] = NativeLibrary.ButtonType.BUTTON_ZR
            map[KEY_SELECT] = NativeLibrary.ButtonType.BUTTON_SELECT
            map[KEY_START] = NativeLibrary.ButtonType.BUTTON_START
            map[KEY_HOME] = NativeLibrary.ButtonType.BUTTON_HOME
            map["主摇杆 ↑"] = NativeLibrary.ButtonType.STICK_LEFT_UP
            map["主摇杆 ↓"] = NativeLibrary.ButtonType.STICK_LEFT_DOWN
            map["主摇杆 ←"] = NativeLibrary.ButtonType.STICK_LEFT_LEFT
            map["主摇杆 →"] = NativeLibrary.ButtonType.STICK_LEFT_RIGHT
            map["C摇杆 ↑"] = NativeLibrary.ButtonType.STICK_C_UP
            map["C摇杆 ↓"] = NativeLibrary.ButtonType.STICK_C_DOWN
            map["C摇杆 ←"] = NativeLibrary.ButtonType.STICK_C_LEFT
            map["C摇杆 →"] = NativeLibrary.ButtonType.STICK_C_RIGHT
            map[App.getContext()
                .getString(R.string.emu_lib_key_name_burst, KEY_A)] =
                VALUE_BURST_A
            map[App.getContext()
                .getString(R.string.emu_lib_key_name_burst, KEY_B)] =
                VALUE_BURST_B
            map[App.getContext()
                .getString(R.string.emu_lib_key_name_burst, KEY_X)] =
                VALUE_BURST_X
            map[App.getContext()
                .getString(R.string.emu_lib_key_name_burst, KEY_Y)] =
                VALUE_BURST_Y
            map[App.getContext()
                .getString(R.string.emu_lib_key_name_burst, KEY_L)] = VALUE_BURST_L
            map[App.getContext()
                .getString(R.string.emu_lib_key_name_burst, KEY_R)] =
                VALUE_BURST_R
            map[App.getContext()
                .getString(R.string.emu_lib_key_name_burst, KEY_ZL)] = VALUE_BURST_ZL
            map[App.getContext()
                .getString(R.string.emu_lib_key_name_burst, KEY_ZR)] =
                VALUE_BURST_ZR
            return map
        }

        fun getDefaultHandleMap(): HashMap<String, Int> {

            val keyMap = HashMap<String, Int>()
            keyMap[KeyEvent.KEYCODE_BUTTON_START.toString() + ""] =
                NativeLibrary.ButtonType.BUTTON_START
            keyMap[KeyEvent.KEYCODE_BUTTON_SELECT.toString() + ""] =
                NativeLibrary.ButtonType.BUTTON_SELECT
            keyMap[KeyEvent.KEYCODE_BUTTON_B.toString() + ""] =
                NativeLibrary.ButtonType.BUTTON_B
            keyMap[KeyEvent.KEYCODE_BUTTON_Y.toString() + ""] =
                NativeLibrary.ButtonType.BUTTON_Y
            keyMap[KeyEvent.KEYCODE_BUTTON_A.toString() + ""] =
                NativeLibrary.ButtonType.BUTTON_A
            keyMap[KeyEvent.KEYCODE_BUTTON_X.toString() + ""] =
                NativeLibrary.ButtonType.BUTTON_X
            keyMap[KeyEvent.KEYCODE_BUTTON_L1.toString() + ""] =
                NativeLibrary.ButtonType.TRIGGER_L
            keyMap[KeyEvent.KEYCODE_BUTTON_R1.toString() + ""] =
                NativeLibrary.ButtonType.TRIGGER_R
            keyMap[KeyEvent.KEYCODE_BUTTON_L2.toString() + ""] =
                NativeLibrary.ButtonType.BUTTON_ZL
            keyMap[KeyEvent.KEYCODE_BUTTON_R2.toString() + ""] =
                NativeLibrary.ButtonType.BUTTON_ZR
            keyMap[MotionEvent.AXIS_HAT_Y.toString() + HandleMapManager.SPLICER + HandleMapManager.AXIS_DIR_NEGATIVE] =
                NativeLibrary.ButtonType.DPAD_UP
            keyMap[MotionEvent.AXIS_HAT_Y.toString() + HandleMapManager.SPLICER + HandleMapManager.AXIS_DIR_POSITIVE] =
                NativeLibrary.ButtonType.DPAD_DOWN
            keyMap[MotionEvent.AXIS_HAT_X.toString() + HandleMapManager.SPLICER + HandleMapManager.AXIS_DIR_NEGATIVE] =
                NativeLibrary.ButtonType.DPAD_LEFT
            keyMap[MotionEvent.AXIS_HAT_X.toString() + HandleMapManager.SPLICER + HandleMapManager.AXIS_DIR_POSITIVE] =
                NativeLibrary.ButtonType.DPAD_RIGHT
            keyMap[MotionEvent.AXIS_Y.toString() + HandleMapManager.SPLICER + HandleMapManager.AXIS_DIR_NEGATIVE] =
                NativeLibrary.ButtonType.STICK_LEFT_UP
            keyMap[MotionEvent.AXIS_Y.toString() + HandleMapManager.SPLICER + HandleMapManager.AXIS_DIR_POSITIVE] =
                NativeLibrary.ButtonType.STICK_LEFT_DOWN
            keyMap[MotionEvent.AXIS_X.toString() + HandleMapManager.SPLICER + HandleMapManager.AXIS_DIR_NEGATIVE] =
                NativeLibrary.ButtonType.STICK_LEFT_LEFT
            keyMap[MotionEvent.AXIS_X.toString() + HandleMapManager.SPLICER + HandleMapManager.AXIS_DIR_POSITIVE] =
                NativeLibrary.ButtonType.STICK_LEFT_RIGHT
            keyMap[MotionEvent.AXIS_RZ.toString() + HandleMapManager.SPLICER + HandleMapManager.AXIS_DIR_NEGATIVE] =
                NativeLibrary.ButtonType.STICK_C_UP
            keyMap[MotionEvent.AXIS_RZ.toString() + HandleMapManager.SPLICER + HandleMapManager.AXIS_DIR_POSITIVE] =
                NativeLibrary.ButtonType.STICK_C_DOWN
            keyMap[MotionEvent.AXIS_Z.toString() + HandleMapManager.SPLICER + HandleMapManager.AXIS_DIR_NEGATIVE] =
                NativeLibrary.ButtonType.STICK_C_LEFT
            keyMap[MotionEvent.AXIS_Z.toString() + HandleMapManager.SPLICER + HandleMapManager.AXIS_DIR_POSITIVE] =
                NativeLibrary.ButtonType.STICK_C_RIGHT
            return keyMap
        }
    }
}
